// 导入数据库模块
const db = require('../db/index')

// 导入 jsonwebtoken
const jsonwebtoken = require('jsonwebtoken')
// 定义密钥 - [根据用户自定义, 配合解密使用]
const configKey = require('../config/index')

// 工具类
const ResVo = require('../class/ResVo')
const Utils = require('../utils')

// ** ---------- api 处理逻辑 ---------- **
const login = async (req, res) => {
  // 1、获取登录请求的数据
  const { username, password } = req.body
  // 2、验证登录请求
  if (!(username && password)) {
    return send(ResVo('账号或密码不能为空'))
  }
  // 3、查询登录用户信息
  const findSql = `select * from sys_user where username = ? AND password = ?`
  try {
    // 密码加密解密code...

    // 密码未做加密解密
    const [results] = await db.query(findSql, [username, password])

  
    console.log("🚀🚀 ~ login ~ results:", results)

    // 返回的 results 对象通常包含两个主要的属性：rows 和 fields

    // rows 属性是一个数组，其中每个元素都是一个对象，表示查询结果中的一行。每个对象的键对应于查询结果的列名，值则是对应列的值。

    // fields 属性也是一个数组，其中每个元素都是一个对象，描述了查询结果中一列的元数据，如列名、数据类型等。
    // 未查询成功
    if (results.length === 0) {
      return res.send(ResVo.err('用户名或密码错误'))
    }

    // 查询成功
    // 3、将返回的数据格式化 - [主要是 下划线写法转为驼峰]
    const transformedResults = Utils.transformedResults(results)
    // 4、剔除隐私数据 - 如密码
    const userInfo = {
      ...transformedResults[0],
      password: ''
    }

    // 5、设置token并存入userInfo并响应给客户端
    const tokenStr = generateToken(userInfo)
    res.send({
      code: 200,
      msg: '登录成功',
      token: 'Bearer ' + tokenStr // token信息 - [注意 Bearer后有个空格]
    })
  } catch (err) {
    console.warn(err.message)
  }
}

// 导入 黑名单存储
const blackList = require('../config/blackList')
// 退出登录
const logout = (req, res) => {
  // 1、从请求头中获取到存储的token
  const token = req.headers.authorization.split(' ')[1] // 剔除 "Bearer "

  // 2、加入黑名单
  blackList.add(token)

  res.send(ResVo.success('退出成功'))
}

const getUserInfo = async (req, res) => {
  try {
    // 1、通过 token 获取用户信息 jwt 可以通过 .auth属性获取存入token的数据
    const userInfo = req.auth
    const roles = await getRoleKeyByUserId(userInfo.userId)
    if (roles.includes('admin')) {
      res.send({
        code: 200,
        msg: '操作成功',
        userInfo,
        roles: ['admin'], 
        permissions: ['all']
      })
    } else {

      // 按钮权限
      const permissions = []

      res.send({
        code: 200,
        msg: '操作成功',
        userInfo,
        roles,
        permissions: ['']
      })
    }
  } catch (err) {
    console.warn(err)
  }

}

// ** ---------- api 处理逻辑 End---------- **

// ** ---------- func ---------- **

/**
 *  生成JWT - token
 * 登录成功，设置token，使用jsonwebtoken.sign() 方法加密并返回token信息, 有三个入参
 * @param {*}  参数1：用户的信息对象 - 不要放入重要隐私信息 - 如密码
 * @param {*}  参数2：加密的秘钥
 * @param {*}  参数3：配置对象 [options, callback]
 *             options: 配置选项
 *              expiresIn 可以配置当前 token 的有效期 （s、h、d）默认是 秒
 *              algorithm:HS256 默认算法
 *             callback: 回调函数，包含返回的错误
 *
 * 验证token是否过期：jsonwebtoken.verify(token, 加密算法) 返回boolean
 * @returns
 */

function generateToken(payload) {
  return jsonwebtoken.sign(payload, configKey.jwtSecretKey, {
    expiresIn: configKey.expiresIn
  })
}

// 根据userId 获取 user的角色
async function getRoleKeyByUserId(userId) {
  // 先连接 sys_user_role 表和 sys_user 表，再连接 sys_role 表
  const sql = `SELECT r.role_key
    FROM sys_user AS u
    JOIN sys_user_role AS ur ON u.user_id = ur.user_id
    JOIN sys_role AS r ON ur.role_id = r.role_id
    WHERE u.user_id = ?`

  try {
    const [results] = await db.execute(sql, [userId])
    const transformedResults = Utils.transformedResults(results)

    const roles = []
    if (Array.isArray(transformedResults) && transformedResults.length > 0) {
      for (let item of transformedResults) {
        roles.push(item.roleKey)
      }
    }
    return roles
  } catch (err) {
    console.warn(err)
  }
}

// ** ---------- func End---------- **

// 暴露方法
module.exports = {
  login,
  getUserInfo,
  logout
}
